#include <stdio.h>
#include <stdlib.h>
#include "yt_init.h"
#include "yt_sys.h"
#include "yt_error.h"
#include "yt_types.h"
#include "yt_init.h"
#include "yt_vlan.h"
#include "cal_mgm.h"
#include "fal_dispatch.h"
#include "hal_cmm.h"
#include "drv.h"
#include "fal_init.h"
#include "yt_loopdetect.h"
#include "yt_storm_ctrl.h"
#include "yt_mirror.h"
#include "yt_port_isolation.h"
#include "yt_stp.h"
#include "yt_types.h"
#include "cal_bprofile.h"
#include "cal_mgm.h"
#include "chipdef.h"

#define port0 0
#define port1 1
#define port2 2
#define port3 3
#define port4 4
#define port5 5
#define port6 6

#define vlan1 1
#define vlan2 2
#define vlan3 3
#define vlan4 4
#define vlan10 10
#define vlan20 20
#define fid1 1
#define fid2 2
#define fid3 3
#define fid4 4
#define fid10 10
#define fid20 20
#define fid30 30

static int yt9215_vlan_groups_set(yt_unit_t unit, yt_vlan_type_t vlanType, yt_vlan_t vlan, yt_port_mask_t member_portmask, yt_port_mask_t untag_portmask, yt_fid_t fid, yt_vlan_t igrPvid)
{
    yt_vlan_fid_set(unit, vlan, fid);
    yt_vlan_port_set(unit, vlan, member_portmask, untag_portmask);

    for (int iport = 0; iport < 5; iport++) {
        if (member_portmask.portbits[0] & (1 << iport)) {
            yt_vlan_port_igrPvid_set(unit, vlanType, iport, igrPvid);
            yt_vlan_port_egrTagMode_set(unit, vlanType, iport, VLAN_TAG_MODE_ENTRY_BASED);
            yt_vlan_port_igrFilter_enable_set(unit, iport, YT_ENABLE);
            yt_vlan_port_egrFilter_enable_set(unit, iport, YT_ENABLE);
            }
    }


    return CMM_ERR_OK;
}

static int yt9215_port_all_status_get(yt_unit_t unit, yt_port_t port, yt_port_linkStatus_all_t *pAllLinkStatus)
{
    int Ret;
    Ret = yt_port_link_status_all_get(unit, port, pAllLinkStatus);
    if(Ret != CMM_ERR_OK){
        return CMM_ERR_FAIL;
    }

    printf("yt9215: Port[%d]\r\n",port);

    switch(pAllLinkStatus->link_status){
        case 0:
            printf("Link down\r\n");
            break;
        case 1:
            printf("Link up\r\n");
            break;
    }

    switch(pAllLinkStatus->link_speed){
        case 0:
            printf("speed is 10M\r\n");
            break;
        case 1:
            printf("speed is 100M\r\n");
            break;
        case 2:
            printf("speed is 1000M\r\n");
            break;
        case 3:
            printf("speed is 2.5G\r\n");
            break;
    }

    switch(pAllLinkStatus->link_duplex){
        case 0:
            printf("duplex is half\r\n");
            break;
        case 1:
            printf("duplex is full\r\n");
            break;
    }

    switch(pAllLinkStatus->rx_fc_en){
        case 0:
            printf("rx_fc_en is disable\r\n");
            break;
        case 1:
            printf("rx_fc_en is enable\r\n");
            break;
    }

    switch(pAllLinkStatus->tx_fc_en){
        case 0:
            printf("tx_fc_en is disable\r\n");
            break;
        case 1:
            printf("tx_fc_en is enable\r\n");
            break;
    }
    printf("\r\n");  
    return CMM_ERR_OK;
}

int main(int argc, char const *argv[]){
    yt_unit_t unit = 0;
    uint32_t phy_addr = 0x1d;
    int param1 = -1;
    uint32_t param2 = 0xdead;

    int ret;
    int iPort = 0;
    int vlan = 0;
    int fid = 0;
    int igrPvid = 0;
    yt_port_linkStatus_all_t LinkStatus;
    yt_vlan_type_t vlanType = VLAN_TYPE_CVLAN;
    yt_port_mask_t untag_portmask;
    yt_port_mask_t member_portmask;

    yt_stat_mib_port_cnt_t pCnt;

    printf("Start API Test Function\n");

    if(yt_init()){
        printf("yt_init error 01\n");
        return CMM_ERR_FAIL;
    }
        
    // phy_operation(phy_addr);
    
    if(strcmp(argv[1], "help") == 0 ){
        printf("\r\n");
        printf("Please use the following command to run the API test function:\n");
        printf("port get port [n] linkstatus\r\n");
        printf("vlan_group1/vlan_group2/vlan_group3/vlan_group4/vlan_group5\r\n");
        printf("mib set state enable\n");
        printf("mib get  [n] state\n");
        printf("mib clear port [n]\n");
        printf("mib clear all\n");
        printf("\r\n");
        
    }else if(strcmp(argv[1], "vlan_group1") == 0 || strcmp(argv[1], "vlan_group2") == 0 || strcmp(argv[1], "vlan_group3") == 0 \
            || strcmp(argv[1], "vlan_group4") == 0 || strcmp(argv[1], "vlan_group5") == 0){

        printf("vlan member_portmask: ");
        scanf("%x", &member_portmask.portbits[0]);

        printf("vlan untag_portmask: ");
        scanf("%x", &untag_portmask.portbits[0]);

        printf("vlan: ");
        scanf("%d", &vlan);

        printf("fid: ");
        scanf("%d", &fid);

        printf("igrPvid: ");
        scanf("%d", &igrPvid);

        ret = yt9215_vlan_groups_set(unit, vlanType, vlan, member_portmask, untag_portmask, fid, igrPvid);
        if(ret != CMM_ERR_OK){
            printf("yt9215_vlan_group_set error\n");
            return CMM_ERR_FAIL;
        }
    }else if(strcmp(argv[1], "port") == 0 && strcmp(argv[2], "get") == 0 && strcmp(argv[3], "port") == 0 && strcmp(argv[5], "linkstatus") == 0){
            iPort = atoi(argv[4]);
            ret = yt9215_port_all_status_get(unit, iPort, &LinkStatus);
            if(ret != CMM_ERR_OK){
                return CMM_ERR_FAIL;
            }
            return 0;   
    }else if(strcmp(argv[1], "mib") == 0 && strcmp(argv[2], "set") == 0 && strcmp(argv[3], "state") == 0 && strcmp(argv[4], "enable") == 0){
        yt_stat_mib_enable_set (unit, YT_ENABLE);
    }else if(strcmp(argv[1], "mib") == 0 && strcmp(argv[2], "get") == 0 && strcmp(argv[4], "state") == 0){
        iPort = atoi(argv[3]);
        ret = yt_stat_mib_port_get(unit, iPort, &pCnt);
        if(ret != CMM_ERR_OK){
            printf("yt_stat_mib_port_get error\n");
            return CMM_ERR_FAIL;
        }
        printf("Port %d MIB Counters:\r\n", iPort);
        printf("RX_BROADCAST: %d\r\n", pCnt.RX_BROADCAST);
        printf("RX_PAUSE: %d\r\n", pCnt.RX_PAUSE);
        printf("RX_MULTICAST: %d\r\n", pCnt.RX_MULTICAST);
        printf("RX_FCS_ERR: %d\r\n", pCnt.RX_FCS_ERR);
        printf("RX_ALIGNMENT_ERR: %d\r\n", pCnt.RX_ALIGNMENT_ERR);
        printf("RX_UNDERSIZE: %d\r\n", pCnt.RX_UNDERSIZE);
        printf("RX_FRAGMENT: %d\r\n", pCnt.RX_FRAGMENT);
        printf("RX_64B: %d\r\n", pCnt.RX_64B);
        printf("RX_65_127B: %d\r\n", pCnt.RX_65_127B);
        printf("RX_128_255B: %d\r\n", pCnt.RX_128_255B);
        printf("RX_256_511B: %d\r\n", pCnt.RX_256_511B);
        printf("RX_512_1023B: %d\r\n", pCnt.RX_512_1023B);
        printf("RX_1024_1518B: %d\r\n", pCnt.RX_1024_1518B);
        printf("RX_JUMBO: %d\r\n", pCnt.RX_JUMBO);
        printf("RX_OKBYTE: %lld\r\n", pCnt.RX_OKBYTE);
        printf("RX_NOT_OKBYTE: %lld\r\n", pCnt.RX_NOT_OKBYTE);
        printf("RX_OVERSIZE: %d\r\n", pCnt.RX_OVERSIZE);
        printf("RX_DISCARD: %d\r\n", pCnt.RX_DISCARD);
        printf("TX_BROADCAST: %d\r\n", pCnt.TX_BROADCAST);
        printf("TX_PAUSE: %d\r\n", pCnt.TX_PAUSE);
        printf("TX_MULTICAST: %d\r\n", pCnt.TX_MULTICAST);
        printf("TX_UNDERSIZE: %d\r\n", pCnt.TX_UNDERSIZE);
        printf("TX_64B: %d\r\n", pCnt.TX_64B);
        printf("TX_65_127B: %d\r\n", pCnt.TX_65_127B);
        printf("TX_128_255B: %d\r\n", pCnt.TX_128_255B);
        printf("TX_256_511B: %d\r\n", pCnt.TX_256_511B);
        printf("TX_512_1023B: %d\r\n", pCnt.TX_512_1023B);
        printf("TX_1024_1518B: %d\r\n", pCnt.TX_1024_1518B);
        printf("TX_JUMBO: %d\r\n", pCnt.TX_JUMBO);
        printf("TX_OKBYTE: %lld\r\n", pCnt.TX_OKBYTE);
        printf("TX_COLLISION: %d\r\n", pCnt.TX_COLLISION);
        printf("TX_EXCESSIVE_COLLISION: %d\r\n", pCnt.TX_EXCESSIVE_COLLISION);
        printf("TX_MULTI_COLLISION: %d\r\n", pCnt.TX_MULTI_COLLISION);
        printf("TX_SINGLE_COLLISION: %d\r\n", pCnt.TX_SINGLE_COLLISION);
        printf("TX_OK_PKT: %d\r\n", pCnt.TX_OK_PKT);
        printf("TX_DEFER: %d\r\n", pCnt.TX_DEFER);
        printf("TX_LATE_COLLISION: %d\r\n", pCnt.TX_LATE_COLLISION);
        printf("RX_OAM_COUNTER: %d\r\n", pCnt.RX_OAM_COUNTER);
        printf("TX_OAM_COUNTER: %d\r\n", pCnt.TX_OAM_COUNTER);
        printf("RX_UNICAST: %d\r\n", pCnt.RX_UNICAST);
        printf("TX_UNICAST: %d\r\n", pCnt.TX_UNICAST);
    }else if(strcmp(argv[1], "mib") == 0 && strcmp(argv[2], "clear") == 0 && strcmp(argv[3], "port") == 0){
        iPort = atoi(argv[4]);
        ret = yt_stat_mib_clear(unit, iPort);
        if(ret != CMM_ERR_OK){
            printf("yt_stat_mib_clear error\n");
            return CMM_ERR_FAIL;
        }
    }else if(strcmp(argv[1], "mib") == 0 && strcmp(argv[2], "clear") == 0 && strcmp(argv[3], "all") == 0 && strcmp(argv[4], "port") == 0){
        ret = yt_stat_mib_clear_all(unit);
        if(ret != CMM_ERR_OK){
            printf("yt_stat_mib_clear_all error\n");
            return CMM_ERR_FAIL;
        }
    }
    else if (argc > 1){
        param1 = strtoul(argv[1], NULL, 0);  // convert string to unsigned long int
    }
    else if (argc >= 3){
        param2 = strtoul(argv[2], NULL, 0);
    }

    if(param1 == 9999){
        yt_sys_chip_reset(unit);
        return 0;
        // sleep(5);
    }

    if(param1 >= 0x65000){
        if (param2 != 0xdead)
        {
            yt_sys_register_value_set(unit, param1, param2);
            printf("%x Write: %x\n", param1, param2);
        }else{
            yt_sys_register_value_get(unit, param1, &param2);
            printf("%x Read: %x\n", param1, param2);
        }
        return 0;
    }

    yt_device_close(unit);
    return 0;
}